#ifndef BB_H
#define	BB_H

#include <stdint.h>
#include "../List.h"
#include "../6502.h"

#ifdef	__cplusplus
extern "C" {
#endif

// Basic Block Instruction
// This ADT represents a 6502 machine instruction that belongs to a basic
// block
typedef struct BBInstruction{
    uint16_t    Address;
    uint8_t     Opcode;
    __AddrModes AddressingMode;
    uint8_t     Operands[3];
    uint8_t     Size;
    uint8_t    ControlFlow;
}BBInstruction;

BBInstruction* BBINew(uint16_t Address);

//Basic Block
// This ADT represents a basic block. 
// The first instruction in a basic block is a jump/branch instruction target
// and the last one should be a jump/branch instruction.

// In case a target is discovered in the middle of an already-existing block,
// it should be split into two basic blocks so the code generated for it
// can be executed correctly.

typedef struct BasicBlock{
    uint16_t            StartingAddress;  // Starting Address in PRG-ROM
    __LinkedList*       Instructions;     // List of instruction metadata
    uint16_t            NumInstructions;  // Number of instructions in this BB
    uint16_t            Size;             // The size of this basic block in bytes
} BasicBlock;

//Returns a new basic block. Initializes the instruction linked list.
BasicBlock* BBNew(uint16_t StartingAddress);

//Inserts a instruction into a basic block
void BBInsertInstruction(BasicBlock* BB, BBInstruction* Instruction);

//Returns a pointer to a an instruction located at Address in BB.
//Returns NULL in case it does not find it.
BBInstruction* BBLookupInstruction(BasicBlock* BB, uint16_t Address);

// Splits a basic block into two.
// The new basic block starting address is given by SplitOn.
// Returns BB is no split is done, NULL on error, and a new BB on split.
BasicBlock* BBSplit(BasicBlock* BB, uint16_t SplitOn);

// Basic Block Repository
// This data structure holds a map of all addresses and their respective
// basic blocks

//Initializes Basic Block Repository
void BBRInit(void);

// Refreshes the repository with basic block information
void BBRRefresh(BasicBlock* BB);

//Returns the basic block that contains "address"
BasicBlock* BBRSearch(uint16_t Address);

#ifdef	__cplusplus
}
#endif

#endif	/* BB_H */

